#include <unistd.h>
#include "service.h"
#include "z_logger.h"
#include "aliot.h"
#include "core_mqtt.h"
#include "aiot_mqtt_upload_api.h"
#include "mqtt_upload_private.h"

/*
 * 后续file_name和path可以从数据库读取，暂时直接写死
 */
#define MQTT_UPLOAD_SINGLE_FILE_NAME "1.csv"
#define FILE_AND_FILE_PATH "/opt/seqiot/dists/home/1.csv"

uint8_t g_upload_single_file_buf[MQTT_UPLOAD_DEFAULT_BLOCK_SIZE];

/* 文件上传的回调处理函数，用于读取本地文件 */
int32_t _read_data_handler(const aiot_mqtt_upload_recv_t *packet, uint8_t *data, uint32_t size, void *userdata) {
    FILE *fp;
    fp = fopen(FILE_AND_FILE_PATH, "rb");
    if (!fp) return 0;
    fread(&g_upload_single_file_buf, sizeof(g_upload_single_file_buf), 1, fp);
    fclose(fp);


    int32_t read_len = 0;
    static uint32_t offset = 0;
    if (userdata != NULL) {
        uint32_t *test_userdata = (uint32_t *) userdata;
        printf("test_userdata:%d\r\n", *test_userdata);
    }
    if (packet == NULL) {
        return 0;
    }

    if (packet->desc.code == UPLOAD_FILE_OK) {
        if (data != NULL && size != 0) {
            if (offset < sizeof(g_upload_single_file_buf)) {
                memcpy(data, g_upload_single_file_buf + offset, size);
                offset += size;
                read_len = size;
            }
        }
    } else {
        printf("Error code:%d, message:%s\r\n", packet->desc.code, packet->desc.message);
    }

    return read_len;
}

static void *_upload_service_init(aliot_service_args_t *args) {
    void *upload_handle = aiot_mqtt_upload_init();

    aiot_mqtt_upload_setopt(upload_handle, AIOT_MQTT_UPLOADOPT_MQTT_HANDLE, args->mqtt_handle);

    uint32_t rsp_timeout = MQTT_UPLOAD_DEFAULT_RSP_TIMEOUT;
    aiot_mqtt_upload_setopt(upload_handle, AIOT_MQTT_UPLOADOPT_RSP_TIMEOUT_MS, &rsp_timeout);

    uint32_t rety_count = MQTT_UPLOAD_DEFAULT_RETRY_MAX_COUNT;
    aiot_mqtt_upload_setopt(upload_handle, AIOT_MQTT_UPLOADOPT_RETRY_COUNT, &rety_count);

    uint32_t block_size = MQTT_UPLOAD_DEFAULT_BLOCK_SIZE;
    aiot_mqtt_upload_setopt(upload_handle, AIOT_MQTT_UPLOADOPT_DEFAULLT_BLOCK_SIZE, &block_size);

    aiot_mqtt_upload_file_opt_t file_opt = {
            .file_name = MQTT_UPLOAD_SINGLE_FILE_NAME,
            .file_size = MQTT_UPLOAD_DEFAULT_BLOCK_SIZE,
            .mode = AIOT_MQTT_UPLOAD_FILE_MODE_OVERWRITE,
            .digest = NULL,
            .read_data_handler = _read_data_handler,
            .userdata = NULL,
    };
    aiot_mqtt_upload_setopt(upload_handle, AIOT_MQTT_UPLOADOPT_FILE_OPTION, &file_opt);

    return upload_handle;
}

static void _upload_service_fini(void **handle) {
    aiot_mqtt_upload_deinit(handle);
}

static char *_upload_file_name(void *handle) {
    mqtt_upload_handle_t *up_handle = handle;

    upload_file_task_handle_t *entry = NULL;
    core_list_for_each_entry(entry, &up_handle->file_list, linked_node, upload_file_task_handle_t) {
        return entry->file_name;
    }

    return NULL;
}

static void *_upload_service_start(void *handle) {
    int32_t res = aiot_mqtt_upload_open_stream(handle, _upload_file_name(handle), NULL);
    if (res != STATE_SUCCESS) {
        aliot_error_check("aiot_mqtt_upload_open_stream", res);
        return NULL;
    }

    while (running) {
        aiot_mqtt_upload_result_t result = aiot_mqtt_upload_process(handle);

        if (result.status == STATE_MQTT_UPLOAD_FINISHED) {
            log_info("MQTT Upload file(%s) success", result.file_name);
            break;
        } else if (result.status == STATE_MQTT_UPLOAD_FAILED ||
                   result.status == STATE_MQTT_UPLOAD_FAILED_TIMEOUT ||
                   result.status == STATE_MQTT_UPLOAD_CANCEL_FAILED) {
            log_warn("MQTT Upload file(%s) failed, res:-0x%.4X", result.file_name, -result.status);
        } else if (result.status == STATE_MQTT_UPLOAD_CANCEL_SUCCESS) {
            log_warn("MQTT Upload file(%s) cancel success, res:-0x%.4X", result.file_name, -result.status);
        } else if (result.status == STATE_MQTT_UPLOAD_FAILED_WHOLE_CHECK) {
            log_warn("MQTT Upload file(%s) whole file md5 failed, res:-0x%.4X", result.file_name, -result.status);
        }
    }

    return NULL;
}

static int32_t _upload_service_stop(void *handle) {
    aiot_mqtt_upload_cancel_stream(handle, _upload_file_name(handle));
    return STATE_SUCCESS;
}

static aliot_service_t _upload_service = {
        .name = MQTT_UPLOAD_MODULE_NAME,
        .init = _upload_service_init,
        .fini = _upload_service_fini,
        .start = _upload_service_start,
        .stop = _upload_service_stop,
};

aliot_service_t *upload_service_get() {
    return &_upload_service;
}
